#pragma once
#include<vector>
#include<string>
#include"BitSet.h"
namespace Long
{
	struct HashStr1
	{
		size_t operator()(const std::string& s)
		{
			size_t num = 0;
			for (int i = 0; s.size(); i++)
			{
				num *= 131;
				num += s[i];
			}
			return num;
		}
	};
	struct HashStr2
	{
		size_t operator()(const std::string& s)
		{
			size_t hash = 0;
			// SDBMHash
			for (size_t i = 0; i < s.size(); ++i)
			{
				hash *= 65599;
				hash += s[i];
			}

			return hash;
		}
	};
	struct HashStr3
	{
		size_t operator()(const std::string& s)
		{
			size_t hash = 0;
			// RSHash
			size_t magic = 63689;
			for (size_t i = 0; i < s.size(); ++i)
			{
				hash *= magic;
				hash += s[i];
				magic *= 378551;
			}

			return hash;
		}
	};
	template<size_t N,class Hash1=HashStr1,class Hash2=HashStr2,class Hash3=HashStr3>
	class BloomFiter
	{
	private:
		bit::BitSet<5 * N> _ta;
		size_t len = 5 * N;
	public:
		void set(const std::string& s)
		{
			Hash1 t1;
			Hash2 t2;
			Hash3 t3;
			size_t n1 = t1(s)%len;
			size_t n2 = t2(s)%len;
			size_t n3 = t3(s)%len;
			
			_ta.set(n1);
			_ta.set(n2);
			_ta.set(n3);
		}
		bool test(const std::string &s)
		{
			Hash1 t1;
			Hash2 t2;
			Hash3 t3;
			size_t n1 = t1(s) % len;
			if (_ta.test(n1) == false)
				return false;
			size_t n2 = t2(s) % len;
			if (_ta.test(n2) == false)
				return false;
			size_t n3 = t3(s) % len;
			if (_ta.test(n3) == false)
				return false;

		}
	};
	/*struct HashFunc
	{
		size_t operator()(const std::string& s)
		{
			size_t num = 0;
			for (size_t i = 0; i < s.size(); i++)
			{
				num *= 131;
				num += s[i];
			}
			return num;
		}
	};
	template<size_t N,class Hash=HashFunc>
	class BloomFiter
	{
	private:
		std::vector<char> _ta;
	public:
		BloomFiter()
		{
			_ta.resize(N/8+1);
		}
		void set(const std::string& s)
		{
			Hash t;
			size_t tmp = t(s);
			size_t len = _ta.size() * 8;
			size_t index = tmp%len;

			size_t i = index / 8;
			size_t j = index % 8;
			_ta[i]=_ta[i] | (1 << j);
		}
		void reset(const std::string&s)
		{
			Hash t;
			size_t tmp = t(s);
			size_t len = _ta.size() * 8;
			size_t index = tmp%len;

			size_t i = index / 8;
			size_t j = index % 8;
			_ta[i]=_ta[i] & (~(1 << j));
		}
		bool test(const std::string& s)
		{
			Hash t;
			size_t tmp = t(s);
			size_t len = _ta.size() * 8;
			size_t index = tmp%len;

			size_t i = index / 8;
			size_t j = index % 8;
			return (_ta[i] & (1 << j)) != 0 ? true : false;
		}
		void Test3()
		{
		Long::BloomFiter<10> t;
		std::string arr[] = { "abcd", "svfc", "gasf" };
		for (auto e : arr)
		{
		t.set(e);
		}
		cout << t.test("abcd") << endl;
		t.reset("abcd");
		cout << t.test("abcd") << endl;
		}
	};*/
}